Skip to content

Fix find_additional_properties ignoring an empty patternProperties key#1522

Open
vineethsaivs wants to merge 1 commit into
python-jsonschema:mainfrom
vineethsaivs:fix/additional-props-empty-pattern
Open

Fix find_additional_properties ignoring an empty patternProperties key#1522
vineethsaivs wants to merge 1 commit into
python-jsonschema:mainfrom
vineethsaivs:fix/additional-props-empty-pattern

Conversation

@vineethsaivs

Copy link
Copy Markdown

find_additional_properties in jsonschema/_utils.py collapses every patternProperties key into one regex with "|".join(...) and then guards it with if patterns:

patterns = "|".join(schema.get("patternProperties", {}))
for property in instance:
    if property not in properties:
        if patterns and re.search(patterns, property):
            continue
        yield property

"|".join maps both an empty patternProperties and {"": ...} to the same empty string, and if patterns then treats that empty (match-everything) pattern as absent. So an empty-string pattern key, which is a valid regex that matches every property, is silently dropped: its properties are reported as additional and validated against additionalProperties instead of the pattern subschema.

from jsonschema import Draft202012Validator as D

# "" matches every property, so patternProperties owns "x"; nothing is additional.
list(D({"additionalProperties": False,
        "patternProperties": {"": {"type": "integer"}}}).iter_errors({"x": 1}))
# before: ["'x' does not match any of the regexes: ''"]   (should be valid)

# The wrong subschema is applied, not just a spurious message:
list(D({"patternProperties": {"": {"type": "string"}},
        "additionalProperties": {"type": "integer"}}).iter_errors({"x": "hi"}))
# before: ["'hi' is not of type 'integer'"]   (should be valid: "x" matches "" -> string subschema)

The sibling helper find_evaluated_property_keys_by_schema (used for unevaluatedProperties) already iterates the patterns individually with re.search, so the two helpers disagree on the same schema. This change makes find_additional_properties do the same: iterate the patternProperties dict and skip a property if any pattern matches, which distinguishes "no patterns" (nothing to match) from an empty-string pattern (matches everything).

Added TestFindAdditionalProperties in jsonschema/tests/test_utils.py (fails before, passes after). The full JSON-Schema-Test-Suite still passes with no regressions.

find_additional_properties joined all patternProperties keys into a single
'|'.join(...) regex and guarded it with 'if patterns', which is falsy for an
empty string. An empty-string pattern key (a valid regex matching every
property) was therefore dropped, so its properties were wrongly treated as
additional and validated against additionalProperties instead of the pattern
subschema. The sibling find_evaluated_property_keys_by_schema already iterates
the patterns individually with re.search; mirror that here.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant